* Boston, MA 02111-1307, USA.
*/
+/* Notes (11/05/99):
+ *
+ * raw pnm, pgm, and pbm files will load now.
+ *
+ * ascii support coming soon.
+ *
+ * next will be incremental loading.
+ */
+
#include <config.h>
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
guint width;
guint height;
+ guint maxval;
PnmFormat type;
guint output_row; /* last row to be completed */
void image_stop_load (gpointer context);
gboolean image_load_increment(gpointer context, guchar *buf, guint size);
+static void explode_bitmap_into_buf (PnmLoaderContext *context);
+static void explode_gray_into_buf (PnmLoaderContext *context);
/* Destroy notification function for the libart pixbuf */
static void
}
-/* explode bitmap data into rgb components */
+/* explode bitmap data into rgb components */
+/* we need to know what the row so we can */
+/* do sub-byte expansion (since 1 byte = 8 pixels) */
+/* context->dptr MUST point at first byte in incoming data */
+/* which corresponds to first pixel of row y */
static void
-explode_bitmap_into_buf (guchar *dptr, guint w)
+explode_bitmap_into_buf (PnmLoaderContext *context)
{
- guchar *p;
- guchar data;
- gint i;
-
- for (p = dptr; (p-dptr) < w; p++) {
- data = *p;
+ gint j;
+ guchar *from, *to, data;
+ gint bit;
+ guchar *dptr;
+ gint wid, x, y;
+
+ g_return_if_fail (context != NULL);
+ g_return_if_fail (context->dptr != NULL);
- for (i=0; i<8; i++, data >> 1)
- *(p+i) = (data & 1) ? 0xff : 0x00;
+ /* I'm no clever bit-hacker so I'm sure this can be optimized */
+ dptr = context->dptr;
+ y = context->output_row;
+ wid = context->width;
+
+ from = dptr + (wid - 1)/8;
+ to = dptr + (wid - 1) * 3;
+ bit = 7 - (((y+1)*wid - 1) % 8);
+
+ /* get first byte and align properly */
+ data = from[0];
+ for (j = 0; j < bit; j++, data >>= 1);
+
+ for (x = wid-1; x >= 0; x--) {
+
+ to[0] = to[1] = to[2] = (data & 1) ? 0x00 : 0xff;
+
+ to -= 3;
+ bit++;
+
+ if (bit > 7) {
+ from--;
+ data = from[0];
+ bit = 0;
+ } else {
+ data >>= 1;
+ }
}
}
/* explode gray image row into rgb components in pixbuf */
static void
-explode_gray_into_buf (guchar *dptr, guint w)
+explode_gray_into_buf (PnmLoaderContext *context)
{
- gint i, j;
+ gint j;
guchar *from, *to;
+ guint w;
- g_return_if_fail (dptr != NULL);
+ g_return_if_fail (context != NULL);
+ g_return_if_fail (context->dptr != NULL);
/* Expand grey->colour. Expand from the end of the
* memory down, so we can use the same buffer.
*/
- from = dptr + w - 1;
- to = dptr + (w - 1) * 3;
+ w = context->width;
+ from = context->dptr + w - 1;
+ to = context->dptr + (w - 1) * 3;
for (j = w - 1; j >= 0; j--) {
to[0] = from[0];
to[1] = from[0];
guchar *ptr;
guint num_left;
- g_return_if_fail (inbuf != NULL);
- g_return_if_fail (inbuf->next_byte != NULL);
+ g_return_val_if_fail (inbuf != NULL, NULL);
+ g_return_val_if_fail (inbuf->next_byte != NULL, NULL);
in_comment = FALSE;
num_left = inbuf->bytes_left;
guchar *ptr;
guint num_left;
- g_return_if_fail (inbuf != NULL);
- g_return_if_fail (inbuf->next_byte != NULL);
+ g_return_val_if_fail (inbuf != NULL, NULL);
+ g_return_val_if_fail (inbuf->next_byte != NULL, NULL);
p = buf;
num_left = inbuf->bytes_left;
guint old_bytes_left;
guchar buf[128];
- g_return_if_fail (inbuf != NULL);
- g_return_if_fail (inbuf->next_byte != NULL);
- g_return_if_fail (value != NULL);
+ g_return_val_if_fail (inbuf != NULL, -1);
+ g_return_val_if_fail (inbuf->next_byte != NULL, -1);
+ g_return_val_if_fail (value != NULL, -1);
old_next_byte = inbuf->next_byte;
old_bytes_left = inbuf->bytes_left;
guchar *old_next_byte;
guint old_bytes_left;
PnmIOBuffer *inbuf;
- guint maxval;
guint w, h;
gint rc;
PnmFormat type;
case PNM_FORMAT_PPM_RAW:
case PNM_FORMAT_PGM:
case PNM_FORMAT_PGM_RAW:
- if ((rc = read_next_number (inbuf, &maxval)) < 0) {
+ if ((rc = read_next_number (inbuf, &context->maxval)) < 0) {
inbuf->next_byte = old_next_byte;
inbuf->bytes_left = old_bytes_left;
return PNM_SUSPEND;
}
- g_print ("Maximum component value is %d\n", maxval);
+ g_print ("Maximum component value is %d\n", context->maxval);
break;
default:
break;
}
- return 0;
+ return PNM_OK;
}
-/* returns 1 if a scanline was converted, 0 means we ran out of data */
+
static gint
-pnm_read_scanline (PnmLoaderContext *context)
+pnm_read_raw_scanline (PnmLoaderContext *context)
{
guint numpix;
- guint numbytes;
- guchar *dptr;
+ guint numbytes, offset;
PnmIOBuffer *inbuf;
g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
inbuf = &context->inbuf;
- /* read in image data */
- /* for raw formats this is trivial */
switch (context->type) {
case PNM_FORMAT_PBM_RAW:
+ numpix = inbuf->bytes_left * 8;
+ break;
case PNM_FORMAT_PGM_RAW:
+ numpix = inbuf->bytes_left;
+ break;
case PNM_FORMAT_PPM_RAW:
- switch (context->type) {
- case PNM_FORMAT_PBM_RAW:
- numpix = inbuf->bytes_left * 8;
- break;
- case PNM_FORMAT_PGM_RAW:
- numpix = inbuf->bytes_left;
- break;
- case PNM_FORMAT_PPM_RAW:
- numpix = inbuf->bytes_left;
- break;
- }
+ numpix = inbuf->bytes_left/3;
+ break;
+ default:
+ g_warning ("io-pnm.c: Illegal raw pnm type!\n");
+ return PNM_FATAL_ERR;
+ break;
+ }
+
+ numpix = MIN (numpix, context->width - context->output_col);
+
+ if (numpix == 0)
+ return PNM_SUSPEND;
+
+ context->dptr = context->pixels +
+ context->output_row * context->width * 3;
+
+ switch (context->type) {
+ case PNM_FORMAT_PBM_RAW:
+ numbytes = numpix/8;
+ offset = context->output_col/8;
+ break;
+ case PNM_FORMAT_PGM_RAW:
+ numbytes = numpix;
+ offset = context->output_col;
+ break;
+ case PNM_FORMAT_PPM_RAW:
+ numbytes = numpix*3;
+ offset = context->output_col*3;
+ break;
+ default:
+ g_warning ("io-pnm.c: Illegal raw pnm type!\n");
+ break;
+ }
+
+ memcpy (context->dptr + offset, inbuf->next_byte, numbytes);
+
+ inbuf->next_byte += numbytes;
+ inbuf->bytes_left -= numbytes;
+
+ context->output_col += numpix;
+ if (context->output_col == context->width) {
+ if ( context->type == PNM_FORMAT_PBM_RAW )
+ explode_bitmap_into_buf(context);
+ else if ( context->type == PNM_FORMAT_PGM_RAW )
+ explode_gray_into_buf (context);
+
+ context->output_col = 0;
+ context->output_row++;
+
+ } else {
+ return PNM_SUSPEND;
+ }
+
+ return PNM_OK;
+}
+
+
+static gint
+pnm_read_ascii_scanline (PnmLoaderContext *context)
+{
+ guint numpix;
+ guint numbytes, offset;
+ gint rc;
+ guint value, numval, i;
+ guchar data;
+ guchar mask;
+ guchar *old_next_byte, *dptr;
+ guint old_bytes_left;
+ PnmIOBuffer *inbuf;
+
+ g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
+
+ inbuf = &context->inbuf;
- numpix = MIN (numpix, context->width - context->output_col);
+ context->dptr = context->pixels +
+ context->output_row * context->width * 3;
- if (numpix == 0)
+ switch (context->type) {
+ case PNM_FORMAT_PBM:
+ mask = 0x80;
+ data = 0;
+ numval = 8;
+ break;
+ case PNM_FORMAT_PGM:
+ numval = 1;
+ break;
+ case PNM_FORMAT_PPM:
+ numval = 3;
+ break;
+
+ default:
+ g_warning ("Can't happen\n");
+ return PNM_FATAL_ERR;
+ }
+
+ old_next_byte = inbuf->next_byte;
+ old_bytes_left = inbuf->bytes_left;
+ dptr = context->dptr;
+
+ for (i=0; i<numval; i++) {
+ if ((rc = read_next_number (inbuf, &value))) {
+ inbuf->next_byte = old_next_byte;
+ inbuf->bytes_left = old_bytes_left;
return PNM_SUSPEND;
+ }
+ printf ("0x%x ", value);
+ fflush (stdout);
switch (context->type) {
- case PNM_FORMAT_PBM_RAW:
- numbytes = numpix/8;
+ case PNM_FORMAT_PBM:
+ if (value)
+ data |= mask;
+ mask >>= 1;
+
break;
- case PNM_FORMAT_PGM_RAW:
- numbytes = numpix;
+ case PNM_FORMAT_PGM:
+ *dptr++ = (guchar)(255.0*((double)value/(double)context->maxval));
break;
- case PNM_FORMAT_PPM_RAW:
- numbytes = numpix*3;
+ case PNM_FORMAT_PPM:
+ *dptr++ = (guchar)(255.0*((double)value/(double)context->maxval));
+ break;
+ default:
+ g_warning ("io-pnm.c: Illegal raw pnm type!\n");
break;
}
+ }
+ if (context->type == PNM_FORMAT_PBM)
+ *dptr++ = value;
- dptr = context->pixels +
- context->output_row * context->width * 3 +
- context->output_col;
-
- memcpy (dptr, inbuf->next_byte, numpix);
-
+ context->output_col++;
+ if (context->output_col == context->width) {
if ( context->type == PNM_FORMAT_PBM_RAW )
- explode_bitmap_info_buf (dptr, numpix);
+ explode_bitmap_into_buf(context);
else if ( context->type == PNM_FORMAT_PGM_RAW )
- explode_gray_info_buf (dptr, numpix);
+ explode_gray_into_buf (context);
+
+ context->output_col = 0;
+ context->output_row++;
+
+ } else {
+ return PNM_SUSPEND;
+ }
+
+ return PNM_OK;
+}
+
+/* returns 1 if a scanline was converted, 0 means we ran out of data */
+static gint
+pnm_read_scanline (PnmLoaderContext *context)
+{
+ gint rc;
+
+ g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
+
+ /* read in image data */
+ /* for raw formats this is trivial */
+ switch (context->type) {
+ case PNM_FORMAT_PBM_RAW:
+ case PNM_FORMAT_PGM_RAW:
+ case PNM_FORMAT_PPM_RAW:
+ rc = pnm_read_raw_scanline (context);
+ if (rc == PNM_SUSPEND)
+ return rc;
+ break;
+
+ case PNM_FORMAT_PBM:
+ case PNM_FORMAT_PGM:
+ case PNM_FORMAT_PPM:
+#if 0
+
+ rc = pnm_read_ascii_scanline (context);
+ if (rc == PNM_SUSPEND)
+ return rc;
+ break;
+#endif
+
+
default:
g_print ("Cannot load these image types (yet)\n");
return PNM_FATAL_ERR;
}
+
+ return PNM_OK;
}
/* Shared library entry point */
GdkPixbuf *
image_load (FILE *f)
{
- guint w, h, i;
- guchar *pixels = NULL;
- guchar *dptr;
- guchar buf[PNM_BUF_SIZE];
guint nbytes;
- guint chunksize;
gint rc;
PnmLoaderContext context;
/* keep buffer as full as possible */
num_to_read = PNM_BUF_SIZE - inbuf->bytes_left;
- if (inbuf->next_byte != NULL)
+ if (inbuf->next_byte != NULL && inbuf->bytes_left > 0)
memmove (inbuf->buffer, inbuf->next_byte,
inbuf->bytes_left);
- nbytes = fread (inbuf->buffer, 1, num_to_read, f);
+ nbytes = fread (inbuf->buffer+inbuf->bytes_left,
+ 1, num_to_read, f);
inbuf->bytes_left += nbytes;
inbuf->next_byte = inbuf->buffer;
context.output_row = 0;
context.output_col = 0;
- pixels = g_malloc (context.height *
+ context.pixels = g_malloc (context.height *
context.width * 3);
- if (!pixels)
+ if (!context.pixels)
return NULL;
g_print ("prescan complete\n");
/* if we got here we're reading image data */
while (context.output_row < context.height) {
-
- g_print ("reading row %d ...",context.output_row+1);
-
rc = pnm_read_scanline (&context);
if (rc == PNM_SUSPEND) {
- g_print ("suspended\n");
break;
} else if (rc == PNM_FATAL_ERR) {
if (context.pixels)
g_warning ("io-pnm.c: error reading rows..\n");
return NULL;
}
- g_print ("completed\n");
}
if (context.output_row < context.height)
break;
}
-
-#if 0
- dptr = buf;
-
- switch (type) {
- case PNM_FORMAT_PPM:
- case PNM_FORMAT_PGM:
- if ((val = skip_ahead_whitespace (f)) < 0)
- return NULL;
- buf[0] = val;
- if (read_til_whitespace (f, buf+1, PNM_BUF_SIZE) < 0)
- return NULL;
-
- maxval = strtol (buf, &errptr, 10);
-
- g_print ("Maximum component value is %d\n", maxval);
- if (*errptr != '\0')
- return NULL;
- break;
- default:
- break;
- }
-
- fflush(stdout);
-
- /* read in image data */
- /* for raw formats this is trivial */
- switch (type) {
- case PNM_FORMAT_PBM_RAW:
- chunksize = w/8;
- case PNM_FORMAT_PGM_RAW:
- chunksize = w;
- case PNM_FORMAT_PPM_RAW:
- chunksize = 3*w;
-
- dptr = pixels;
- while (!feof (f)) {
- nbytes = fread (dptr, 1, chunksize, f);
- if (nbytes < chunksize && nbytes != 0) {
- g_free (pixels);
- return NULL;
- }
-
- if ( type == PNM_FORMAT_PBM_RAW )
- explode_bitmap_info_buf (dptr, w);
- else if ( type == PNM_FORMAT_PGM_RAW )
- explode_gray_info_buf (dptr);
-
- dptr += 3*w;
- }
-
- /* did we get the entire image? */
- if ((dptr - pixels) != 3*w*(h+1)) {
- g_free (pixels);
- return NULL;
- }
-
- break;
- default:
- g_print ("Couldnt load image data (yet)\n");
- fflush(stdout);
- return NULL;
- }
-
- return gdk_pixbuf_new_from_data (pixels, ART_PIX_RGB, FALSE,
- w, h, w * 3,
- free_buffer, NULL);
-#endif
+ return gdk_pixbuf_new_from_data (context.pixels, ART_PIX_RGB, FALSE,
+ context.width, context.height,
+ context.width * 3, free_buffer, NULL);
}